package org.example.services.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.example.Exception.RollBackException;
import org.example.dao.CommentDao;
import org.example.dao.DiscussionDao;
import org.example.dao.UserDao;
import org.example.domain.Discussion;
import org.example.domain.EsDiscussion;
import org.example.domain.PageBean;
import org.example.domain.User;
import org.example.domain.response.ResponseResult;
import org.example.repository.ESDiscussionRepository;
import org.example.services.DiscussionService;
import org.example.utils.PageConvertPageBeanUtil;
import org.example.utils.RedisCache;
import org.example.utils.TokenUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.querydsl.QPageRequest;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.thymeleaf.util.ArrayUtils;
import org.thymeleaf.util.ListUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.validation.constraints.NotNull;
import java.util.List;
import java.util.Map;

import static org.example.config.kafkaConsumer.KAFKA_TOPIC;

@Service
@Slf4j
@Transactional
public class DiscussionServiceImpl implements DiscussionService {

    @Resource
    private DiscussionDao discussionDao;
    @Resource
    private UserDao userDao;
    @Resource
    private CommentDao commentDao;
    @Autowired
    private RedisCache redisCache;
    @Resource
    KafkaTemplate<String,String> kakfa;
    @Autowired
    private ESDiscussionRepository  esDiscussionRepository;

    @Override
    public ResponseResult saveDiscussion(Discussion discussion) {
        try {
            User user = userDao.selectById(discussion.getUserId());
            if(user == null){
                log.info("新增讨论：用户ID不存在");
                return ResponseResult.failed("用户不存在");
            }
            discussionDao.insert(discussion);
            discussionDao.setContentByDiscussionId(discussion.getDiscussionId(),discussion.getContent());
            EsDiscussion esDiscussion = new EsDiscussion();
            BeanUtils.copyProperties(discussion,esDiscussion);
            esDiscussion.setId(discussion.getDiscussionId().toString());
            esDiscussionRepository.save(esDiscussion);
            log.info("新增讨论：成功{}",discussion);
            return ResponseResult.success("新增讨论成功",discussion);
        } catch (Exception e) {
            e.printStackTrace();
            log.info("新增讨论：失败");
            throw new RollBackException("新增讨论失败");
        }
    }

    @Override
    public ResponseResult updateDiscussion(Discussion discussion) {
        try {
            Discussion discussionRes = discussionDao.selectById(discussion.getDiscussionId());
            if(discussionRes == null){
                log.info("修改讨论：讨论ID{}不存在",discussion.getDiscussionId());
                return ResponseResult.failed("无该讨论信息，请刷新");
            }
            discussionDao.updateById(discussion);
            if(discussion.getContent() != null){
                discussionDao.updateContentByDiscussionId(discussion.getDiscussionId(),discussion.getContent());
            }
            EsDiscussion esDiscussion = new EsDiscussion();
            BeanUtils.copyProperties(discussion,esDiscussion);
            esDiscussion.setId(discussion.getDiscussionId().toString());
            esDiscussionRepository.save(esDiscussion);
            log.info("修改讨论：成功{}",discussion);
            return ResponseResult.success("修改成功",null);
        } catch (Exception e) {
            e.printStackTrace();
            log.warn("修改讨论：失败");
            throw new RollBackException("修改讨论失败");
        }
    }

    @Override
    public ResponseResult userLikeDiscussion(int userId, int discussionId) {
        try {
            User user = userDao.selectById(userId);
            if(user == null){
                log.info("用户点赞讨论：用户ID不存在");
                return ResponseResult.failed("用户不存在");
            }
            Discussion discussion = discussionDao.selectById(discussionId);
            if(discussion == null){
                log.info("用户点赞讨论：无该讨论{}",discussionId);
                return ResponseResult.failed("无该讨论，请刷新");
            }
            discussionDao.LikeAdd(discussionId);
            log.info("用户点赞讨论：成功");
            return ResponseResult.success("点赞成功",null);
        } catch (Exception e) {
            e.printStackTrace();
            log.warn("用户点赞讨论：失败");
            return ResponseResult.failed("点赞失败，请重试");
        }
    }

    @Override
    public ResponseResult getDiscussionById(int discussionId, HttpServletRequest request) {
        try {
            //通过token获取当前点击查看用户ID
            String token = request.getHeader("token");
            Integer userId = TokenUtils.getUserToken(token).getUserId();
            Discussion discussion = discussionDao.selectById(discussionId);
            String type = discussion.getType();
            log.info("{}用户点击了讨论类型：{}",userId,type);
            //由于在本地，虚拟机上的flume获取不到日志，直接用kafka发送
            kakfa.send(KAFKA_TOPIC,userId + "用户点击了讨论类型：" + type);

            if(discussion == null){
                log.info("获取讨论详情：无该讨论{}",discussionId);
                return ResponseResult.failed("无该讨论，请刷新");
            }
            discussionDao.clickAdd(discussionId);
            String content = discussionDao.getContentByDiscussionId(discussionId);
            discussion.setContent(content);
            log.info("获取讨论详情：成功{}",discussion);
            return ResponseResult.success("获取讨论详情成功",discussion);
        } catch (Exception e) {
            e.printStackTrace();
            log.warn("通过讨论ID查看讨论详情：失败");
            return ResponseResult.failed("获取讨论详情失败");
        }
    }

    @Override
    public ResponseResult getDiscussionByPage(int pageSize, int currentPage) {
        try {
            Page<Discussion> page = new Page<>(currentPage, pageSize);
            LambdaQueryWrapper<Discussion> discussionLambdaQueryWrapper = new LambdaQueryWrapper<>();
            discussionLambdaQueryWrapper.orderByDesc(Discussion::getCreateTime);
            Page<Discussion> discussionPage = discussionDao.selectPage(page, discussionLambdaQueryWrapper);
            PageBean<Discussion> pageBean = PageConvertPageBeanUtil.convert(discussionPage);
            addCommentNumberAndContentAndUserAvatar(pageBean);
            log.info("分页查询讨论：成功{}",pageBean);
            return ResponseResult.success("分页查询讨论成功",pageBean);
        } catch (Exception e) {
            e.printStackTrace();
            log.warn("分页查询讨论：失败");
            return ResponseResult.failed("分页查询讨论失败");
        }
    }

    @Override
    public ResponseResult getDiscussionOrderByLikes(int currentPage) {
        try {
            Page<Discussion> page = new Page<>(currentPage, 10);
            LambdaQueryWrapper<Discussion> discussionLambdaQueryWrapper = new LambdaQueryWrapper<>();
            discussionLambdaQueryWrapper.orderByDesc(Discussion::getLikes);
            Page<Discussion> discussionPage = discussionDao.selectPage(page, discussionLambdaQueryWrapper);
            PageBean<Discussion> pageBean = PageConvertPageBeanUtil.convert(discussionPage);
            addCommentNumberAndContentAndUserAvatar(pageBean);
            log.info("分页查询讨论：成功{}",pageBean);
            return ResponseResult.success("分页查询讨论成功",pageBean);
        } catch (Exception e) {
            e.printStackTrace();
            log.warn("分页查询讨论：失败");
            return ResponseResult.failed("分页查询讨论失败");
        }
    }

    @Override
    public ResponseResult getDiscussionOrderByClick(int currentPage) {
        try {
            Page<Discussion> page = new Page<>(currentPage, 10);
            LambdaQueryWrapper<Discussion> discussionLambdaQueryWrapper = new LambdaQueryWrapper<>();
            discussionLambdaQueryWrapper.orderByDesc(Discussion::getClick);
            Page<Discussion> discussionPage = discussionDao.selectPage(page, discussionLambdaQueryWrapper);
            PageBean<Discussion> pageBean = PageConvertPageBeanUtil.convert(discussionPage);
            addCommentNumberAndContentAndUserAvatar(pageBean);
            log.info("分页查询讨论：成功{}",pageBean);
            return ResponseResult.success("分页查询讨论成功",pageBean);
        } catch (Exception e) {
            e.printStackTrace();
            log.warn("分页查询讨论：失败");
            return ResponseResult.failed("分页查询讨论失败");
        }
    }

    @Override
    public ResponseResult getDiscussionByUserId(int userId, int currentPage) {
        try {
            Page<Discussion> page = new Page<>(currentPage, 10);
            LambdaQueryWrapper<Discussion> discussionLambdaQueryWrapper = new LambdaQueryWrapper<>();
            discussionLambdaQueryWrapper.orderByDesc(Discussion::getCreateTime);
            discussionLambdaQueryWrapper.eq(Discussion::getUserId,userId);
            Page<Discussion> discussionPage = discussionDao.selectPage(page, discussionLambdaQueryWrapper);
            PageBean<Discussion> pageBean = PageConvertPageBeanUtil.convert(discussionPage);
            addCommentNumberAndContentAndUserAvatar(pageBean);
            log.info("通过用户ID分页查询讨论：成功{}",pageBean);
            return ResponseResult.success("分页查询讨论成功",pageBean);
        } catch (Exception e) {
            e.printStackTrace();
            log.warn("通过用户ID分页查询讨论：失败");
            return ResponseResult.failed("查询失败，请稍后重试");
        }
    }

    @Override
    public ResponseResult deleteDiscussionById(int discussionId) {
        try {
            Discussion discussion = discussionDao.selectById(discussionId);
            if(discussion == null){
                log.info("通过ID删除讨论：无该讨论ID{}",discussionId);
                return ResponseResult.failed("无该讨论，请刷新");
            }
            discussionDao.deleteById(discussionId);
            discussionDao.deleteContentByDiscussionId(discussionId);
            commentDao.deleteByDiscussionId(discussionId);
            esDiscussionRepository.deleteById(String.valueOf(discussionId));
            log.info("通过ID删除讨论：成功{}",discussion);
            return ResponseResult.success("删除讨论成功",null);
        } catch (Exception e) {
            e.printStackTrace();
            log.info("通过ID删除讨论：失败");
            throw new RollBackException("删除讨论失败，请稍后重试");
        }
    }

    @Override
    public ResponseResult getDiscussionByTitle(String title, int currentPage) {
        try {
            Page<Discussion> page = new Page<>(currentPage, 10);
            LambdaQueryWrapper<Discussion> discussionLambdaQueryWrapper = new LambdaQueryWrapper<>();
            discussionLambdaQueryWrapper.orderByDesc(Discussion::getCreateTime);
            discussionLambdaQueryWrapper.like(Discussion::getTitle,title);
            Page<Discussion> discussionPage = discussionDao.selectPage(page, discussionLambdaQueryWrapper);
            PageBean<Discussion> pageBean = PageConvertPageBeanUtil.convert(discussionPage);
            addCommentNumberAndContentAndUserAvatar(pageBean);
            log.info("通过讨论主题分页查询讨论：成功{}",pageBean);
            return ResponseResult.success("分页查询讨论成功",pageBean);
        } catch (Exception e) {
            e.printStackTrace();
            log.warn("通过讨论主题分页查询讨论：失败");
            return ResponseResult.failed("查询失败，请稍后重试");
        }
    }

    @Override
    public ResponseResult getDiscussionByType(String type, int currentPage) {
        try {
            Page<Discussion> page = new Page<>(currentPage, 10);
            LambdaQueryWrapper<Discussion> discussionLambdaQueryWrapper = new LambdaQueryWrapper<>();
            discussionLambdaQueryWrapper.orderByDesc(Discussion::getCreateTime);
            discussionLambdaQueryWrapper.eq(Discussion::getType,type);
            Page<Discussion> discussionPage = discussionDao.selectPage(page, discussionLambdaQueryWrapper);
            PageBean<Discussion> pageBean = PageConvertPageBeanUtil.convert(discussionPage);
            addCommentNumberAndContentAndUserAvatar(pageBean);
            log.info("通过讨论类型分页查询讨论：成功{}",pageBean);
            return ResponseResult.success("分页查询讨论成功",pageBean);
        } catch (Exception e) {
            e.printStackTrace();
            log.warn("通过讨论类型分页查询讨论：失败");
            return ResponseResult.failed("查询失败，请稍后重试");
        }
    }
    @Override
    public ResponseResult getDiscussionByCondition(Discussion discussion, int currentPage) {
        try {
            Page<Discussion> page = new Page<>(currentPage, 10);
            LambdaQueryWrapper<Discussion> discussionLambdaQueryWrapper = new LambdaQueryWrapper<>();
            discussionLambdaQueryWrapper.orderByDesc(Discussion::getCreateTime);
            discussionLambdaQueryWrapper.like(null != discussion.getTitle(),Discussion::getTitle,discussion.getTitle());
            discussionLambdaQueryWrapper.eq(null != discussion.getType(),Discussion::getType,discussion.getType());
            discussionLambdaQueryWrapper.eq(0 < discussion.getUserId(),Discussion::getUserId,discussion.getUserId());
            Page<Discussion> discussionPage = discussionDao.selectPage(page, discussionLambdaQueryWrapper);
            PageBean<Discussion> pageBean = PageConvertPageBeanUtil.convert(discussionPage);
            addCommentNumberAndContentAndUserAvatar(pageBean);
            log.info("通过条件分页查询讨论：成功{}",pageBean);
            return ResponseResult.success("分页查询讨论成功",pageBean);
        } catch (Exception e) {
            e.printStackTrace();
            log.warn("通过条件分页查询讨论：失败");
            return ResponseResult.failed("查询失败，请稍后重试");
        }
    }

    @Override
    public ResponseResult getDiscussionByHot(int pageSize, int currentPage) {
        try {
            Page<Discussion> page = new Page<>(currentPage, pageSize);
            LambdaQueryWrapper<Discussion> discussionLambdaQueryWrapper = new LambdaQueryWrapper<>();
            discussionLambdaQueryWrapper.orderByDesc(Discussion::getClick,Discussion::getCreateTime,Discussion::getLikes);
            Page<Discussion> discussionPage = discussionDao.selectPage(page, discussionLambdaQueryWrapper);
            PageBean<Discussion> pageBean = PageConvertPageBeanUtil.convert(discussionPage);
            addCommentNumberAndContentAndUserAvatar(pageBean);
            log.info("分页查询讨论：成功{}",pageBean);
            return ResponseResult.success("分页查询讨论成功",pageBean);
        } catch (Exception e) {
            e.printStackTrace();
            log.warn("分页查询讨论：失败");
            return ResponseResult.failed("分页查询讨论失败");
        }
    }

    @Override
    public ResponseResult getDiscussionByAdvice(int pageSize, int currentPage, int userId) {
        try {
            Page<Discussion> page = new Page<>(currentPage, pageSize);
            LambdaQueryWrapper<Discussion> discussionLambdaQueryWrapper = new LambdaQueryWrapper<>();
            discussionLambdaQueryWrapper.orderByDesc(Discussion::getClick,Discussion::getCreateTime,Discussion::getLikes);
            //查看当前用户的收藏type来推荐相应的讨论
//            List<String> types = userDao.getUserDiscussionTypeById(userId);
//            if(!ListUtils.isEmpty(types)){
//                discussionLambdaQueryWrapper.in(Discussion::getType,types);
//            }
            //通过redis中存贮的用户常查看的讨论类型推荐
            Map<String,Integer> typeMap = redisCache.getCacheObject(userId + "_likes");
            System.out.println("===========================" + typeMap);
            if(typeMap != null){
                //获取点击最多的讨论类型
                Map.Entry<String, Integer> s = typeMap.entrySet().stream().max((s1, s2) -> {
                    return s1.getValue() - s2.getValue();
                }).get();
                System.out.println(s.getKey());
                System.out.println("=======================================进入===========" + s.getKey());
                String key = s.getKey();
                discussionLambdaQueryWrapper.in(Discussion::getType,key);
            }

            Page<Discussion> discussionPage = discussionDao.selectPage(page, discussionLambdaQueryWrapper);
            PageBean<Discussion> pageBean = PageConvertPageBeanUtil.convert(discussionPage);
            addCommentNumberAndContentAndUserAvatar(pageBean);
            log.info("分页查询讨论：成功{}",pageBean);
            return ResponseResult.success("分页查询讨论成功",pageBean);
        } catch (Exception e) {
            e.printStackTrace();
            log.warn("分页查询讨论：失败");
            return ResponseResult.failed("分页查询讨论失败");
        }
    }

    @Override
    public void addCommentNumberAndContentAndUserAvatar(PageBean pageBean){
        List<Discussion> rows = pageBean.getRows();
        for (Discussion row : rows) {
            row.setCommentNumber(commentDao.getNumberByDiscussionId(row.getDiscussionId()));
            row.setContent(discussionDao.getContentByDiscussionId(row.getDiscussionId()));
            row.setUserIcon(userDao.getIcon(row.getUserId()));
        }
    }

    @Override
    public ResponseResult getDiscussionByKey(String key, int pageSize, int currentPage) {
        if(currentPage < 1 || pageSize < 1){
            return ResponseResult.failed("参数错误");
        }
        Pageable qPageRequest = PageRequest.of(currentPage - 1, pageSize);
//        Pageable qPageRequest = PageRequest.of(pageSize*(currentPage - 1), pageSize);
        org.springframework.data.domain.Page<EsDiscussion> esDiscussionPage = esDiscussionRepository.findByTitleOrContentOrType(key, key, key, qPageRequest);
        PageBean<EsDiscussion> esDiscussionPageBean = new PageBean<>();
        esDiscussionPageBean.setTotalPages(esDiscussionPage.getTotalPages());
        esDiscussionPageBean.setTotalData((int) esDiscussionPage.getTotalElements());
        esDiscussionPageBean.setPageSize(pageSize);
        esDiscussionPageBean.setCurrentPage(currentPage);
        esDiscussionPageBean.setRows(esDiscussionPage.getContent());
        //添加讨论用户头像
        List<EsDiscussion> rows = esDiscussionPageBean.getRows();
        for (EsDiscussion row : rows) {
            row.setUserIcon(userDao.getIcon(row.getUserId()));
        }
        //当请求的当前页大于总页数大小
        if(esDiscussionPageBean.getCurrentPage() > esDiscussionPageBean.getTotalPages()){
            esDiscussionPageBean.setCurrentPage(esDiscussionPageBean.getTotalPages());
            qPageRequest = PageRequest.of(esDiscussionPageBean.getTotalPages() - 1, pageSize);
            esDiscussionPage = esDiscussionRepository.findByTitleOrContentOrType(key, key, key, qPageRequest);
            esDiscussionPageBean.setRows(esDiscussionPage.getContent());
        }
        return ResponseResult.success("讨论全局查询成功",esDiscussionPageBean);
    }

    @Override
    public ResponseResult addDiscussionFromMysqlToESById(int discussionId) {
        Discussion discussion = discussionDao.selectById(discussionId);
        if(discussion == null){
            log.info("从数据库添加讨论到ES，讨论ID{}",discussionId);
            return ResponseResult.failed("该讨论ID不存在，请刷新");
        }
        String content = discussionDao.getContentByDiscussionId(discussionId);
        discussion.setContent(content);
        EsDiscussion esDiscussion = new EsDiscussion();
        BeanUtils.copyProperties(discussion,esDiscussion);
        esDiscussion.setId(discussion.getDiscussionId().toString());
        esDiscussionRepository.save(esDiscussion);
        return ResponseResult.success("更新成功",null);
    }
}
